#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <iostream>
#include <string.h>
#include <zlib.h>
#ifndef _WIN32
#include <signal.h>
#endif
using namespace std;

#define FILEPATH "001.txt"

class ClientStatus{
 public:       
        FILE *fp = NULL;
        bool end = false;
        z_stream *z_output = NULL;
        bool startSend = false;
        int readNum = 0;
        int sendNum = 0;

        ~ClientStatus(){
                if(fp){
                        fclose(fp);
                        fp = NULL;
                }
                if(z_output){
                        deflateEnd(z_output);
                        z_output = NULL;
                }
        }
};


void read_cb(struct bufferevent *bev, void *ctx){
        cout <<"read_cb"<<endl;
       
       ClientStatus *s = (ClientStatus *)ctx;

        //接收服务端发送的OK回复
        char data[1024] = { 0 };
        int len = bufferevent_read(bev, data, sizeof(data)-1);
        
        if(strcmp(data, "OK") == 0){
                cout<<"client recv = "<<data<<" len = " << len <<endl;
                s->startSend = true;
                //开始发送文件,触发写入回调
                bufferevent_trigger(bev, EV_WRITE, 0);
        }else{
                bufferevent_free(bev);
        }
}

void write_cb(struct bufferevent *bev, void *ctx){
        cout <<"write_cb"<<endl;
        ClientStatus *s = (ClientStatus *)ctx;

        //判断什么时候清理资源
        if(s->end){
                 //判断缓冲区是否有数据 如果有 刷新
                //获取过滤器绑定的buffer
                bufferevent *not_filter_bev = bufferevent_get_underlying(bev);
                //获取输出缓冲及其大小
                evbuffer *evb = bufferevent_get_output(not_filter_bev);
                int len = evbuffer_get_length(evb);
                if(len <= 0){
                        cout<<"Client read = "<<s->readNum << " send = "<<s->sendNum<<endl;
                        //立刻清理的 如果缓冲有数据 不会发送出去
                        bufferevent_free(bev);
                        delete s;
                        return;
                }
                //刷新缓冲
                //bufferevent_flush(bev,  EV_WRITE, BEV_FINISHED);
                return ;
        }


        FILE *fp = s->fp;
        if(!fp) return ;

        //读取文件
        char data[1024] = {0};
        int len = fread(data, 1, sizeof(data), fp);

        if(len <= 0){
                fclose(fp);
                s->end = true;
                //刷新缓冲
                bufferevent_flush(bev, EV_WRITE, BEV_FINISHED);
                return; 
        }
        
        //发送文件
        bufferevent_write(bev, data, len);
}

bufferevent_filter_result filter_out(
    struct evbuffer *src, struct evbuffer *dst, ev_ssize_t dst_limit,
    enum bufferevent_flush_mode mode, void *ctx){
        cout <<"filter_out"<<endl;
        
        ClientStatus *s = (ClientStatus *)ctx;
        
        //压缩文件
        //发送文件名消息001 去掉
        if(!s->startSend){
                char data[1024] = {0};
                int len = evbuffer_remove(src, data, sizeof(data));
                evbuffer_add(dst, data, len);
                return BEV_OK;
        }

        //开始压缩文件
        //取出buffer中数据的引用
        evbuffer_iovec v_in[1];
        int n = evbuffer_peek(src, -1, 0, v_in, 1);
        if(n <= 0){
                //调用write回调 清理空间
                if(s->end){
                        return BEV_OK;
                }
                //没有数据 不会进入写入回调
                return BEV_NEED_MORE;
        }
        
        if(!s->z_output){
                return BEV_ERROR;
        }

        //zlib 输入数据大小
        s->z_output->avail_in  = v_in[0].iov_len;
        //输入数据地址
        s->z_output->next_in = (Byte *)v_in[0].iov_base;

        //申请输出空间大小
        evbuffer_iovec v_out[1];
        evbuffer_reserve_space(dst, 4096, v_out, 1);

        //zlib 输出空间大小
        s->z_output->avail_out = v_out[0].iov_len;
        //zlib 输出地址
        s->z_output->next_out = (Byte *)v_out[0].iov_base;

        //zlib压缩
        int ret = deflate(s->z_output, Z_SYNC_FLUSH);
        if(ret != Z_OK){
                cerr<<" deflate failed! "<<endl;
                return BEV_ERROR;
        } 

        //压缩用了多少数据 从src evbuffer中移除
        //z_output->avail_in 未处理的数据大小
        int nread = v_in[0].iov_len - s->z_output->avail_in;
        //压缩后数据大小 传入 dst evbuffer
        //s->z_output->avail_out  剩余空间大小
        int nwrite = v_out[0].iov_len - s->z_output->avail_out;

        //移除src evbuffer中数据
        evbuffer_drain(src, nread);

        //传入 dst evbuffer
        v_out[0].iov_len = nwrite;
        evbuffer_commit_space(dst, v_out, 1);
        cout<<"client nread = "<<nread<<" nwrite = "<<nwrite<<endl;

        s->readNum += nread;
        s->sendNum += nwrite;

        return BEV_OK;
}

void event_cb(struct bufferevent *bev, short what, void *ctx){
        cout<<"event _cb = "<< what <<endl;

        if(what & BEV_EVENT_CONNECTED){
                cout<<"BEV_EVENT_CONNECTED "<<endl;
                //发送文件名 文件名不经过过滤器
                bufferevent_write(bev, FILEPATH, strlen(FILEPATH));

                                
                FILE *fp = fopen(FILEPATH, "rb");
                if(!fp){
                        cout<<"open file"<<FILEPATH <<" failed" << endl;
                        return;
                }
                ClientStatus *s = new ClientStatus();
                s->fp = fp;

                //初始化zlib上下文
                s->z_output = new z_stream();
                deflateInit(s->z_output, Z_DEFAULT_COMPRESSION);

                
                //创建输出过滤
                bufferevent *bev_filter = bufferevent_filter_new(bev, NULL, filter_out, 
                        BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS ,  NULL , s); 

                //设置读取 写入 和 事件
                bufferevent_setcb(bev_filter, read_cb, write_cb, event_cb, s);
                bufferevent_enable(bev_filter, EV_READ | EV_WRITE);
        }

}

int main(int argc, char const *argv[]){
#ifdef _WIN32
        //初始化socket库
        WSADATA wsa;
        WSAStartup(MAKEWORD(2,2), &wsa);
#else
        //忽略管道信号 发送数据给已关闭的socket
        if(signal(SIGPIPE,SIG_IGN) == SIG_IGN){
                return 1;
        }
#endif
        event_base *base = event_base_new();

        //连接服务器
        sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(8080);
        evutil_inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr.s_addr);

        bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

        //只绑定事件回调
        bufferevent_enable(bev, EV_READ | EV_WRITE);
        bufferevent_setcb(bev, NULL, NULL, event_cb, base);
        
        bufferevent_socket_connect(bev, (sockaddr *)&sin, sizeof(sin));

        event_base_dispatch(base);

        bufferevent_free(bev);

        event_base_free(base);

        return 0;
}

